One of the real strengths of a SNAP network is the ability to wirelessly update, and even reprogram, nodes within the network. This can be accomplished without taking the network down, so it’s pretty easy to make changes and see the results in near real time.
For this example we’re going to make some simple changes to the code used in another exercise, wirelessly update the node, and then see those results in real time. Before that, we should look at how SNAP and Python work together.
The SN171 protoboard is currently running HolidayLightShow.py. Locate this node (it’s the one with the device type “Buzz”) in the Node Views pane and double-click it to open it in the Node Info pane. The Device Image field will list the script that’s running, and that listing is a hyperlink you can use to load the script into a pane where you can view and edit it. Click this link to load HolidayLightShow.py. into a viewing pane.
SNAP nodes are programmed using SNAPpy, a subset of the Python programming language that is optimized for low-power embedded devices. This exercise assumes you have a basic understanding of the Python programming language. If you’re not familiar with Python, there are a number of resources available for learning it. (The websites www.python.org and www.codeacademy.com are excellent places to start.)
Scrolling through the HolidayLightShow.py script will give you some examples of the basics of a SNAPpy script.
A SNAPpy function is just like a Python function, except there are some SNAP commands like mcast and @setHook spinkled in. We’ll talk more about those commands shortly.
As with any Python program, SNAPpy supports variables. Variables within a SNAPpy script can be particularly valuable when it comes to addressing the GPIOs of a SNAP module. As you can see in the script, descriptive variable names are assigned to the GPIOs that correspond to the attached components. After all, it’s a lot easier to remember the GPIO for the button pin if we’re just referring to it as buttonPin.
There are a number of events in the system that you might like to trigger some SNAPpy function “handler.” When defining your SNAPpy scripts, you can associate functions with these external events by specifying a “HOOK” identifier for the function. Hooks are available for device bootup, pin transitions, data transmission, and time passage among other things. A hook identifier will be in the form @setHook() and will affect the next function listed after it.
In the HolidayLightShow.py script the startupEvent function is defined immediately after the @setHook(HOOK_STARTUP) hook meaning it will be called once on startup. After that, it’ll need to be specifically called if it’s going to be called again.
Later in the script you’ll see the function timer100msEvent defined immediately after @setHook(HOOK_100MS). This means that every 100 milliseconds the timer100msEvent function will be called. In this script, the timer100msEvent is used to increment a timer that calls the doEverySecond function after the passage of one second of time.
This script communicates with other nodes through the use of a remote procedure call, or RPC. There are five kinds of RPCs in SNAPpy, but for this exercise we’re using mcastRPC(), also known as a multicast remote procedure call.
When a SNAP node invokes a multicast call, it’s sending that call to every node that can receive it. In this script you’ll see commands like, “mcastRpc(1,2,”christmasBlink”)” and “mcastRpc(1,2,”halloweenBlink”).” These commands are essentially saying, “Hey! Everyone invoke the christmasBlink/halloweenBlink function!”
The blinking LEDs invoked in the christmasBlink and halloweenBlink functions are generated by the pulsePin function, which can be used any time you need to blink an LED. pulsePin has three configuration parameters.
pulsePin(pin, msWidth, isPositive)
pin - The IO for the pin that corresponds to the LED that you want to blink.
msWdith - The duration (in milliseconds) of the the pulse
isPositive - The polarity of the pulse
In our script, a typical pulsePin looks like:
pulsePin(redLEDPin, 400, True)
redLEDPin gets the GPIO pin for the red LED from the variable at the beginning of the script (In this case, GPIO_4), and msWidth defines the pulse duration as 400 milliseconds. (We’ll skip pulse polarity for now.)
With all that explained, let’s take a look at how easy it is to change a script on a node.
Scroll through the HolidayLightShow.py script until you find the doEverySecond function somewhere around line 85. There are two if statements in this function that define how long the LEDs will each blink. If you click one of the statements and attempt to enter changes, Portal will warn that the file is read only and we’ll need to save it as another filename before changes can be made. Click the “yes” button and save the file as “HolidayLightShow-Experimental.py”.
This is where you can see how easy it is to update a node script via SNAP and Portal.
To change a script:
The import thing to notice here is, you just altered the code and wirelessly reprogrammed a node without attaching a cable to it. This is one of the things that makes SNAP a really easy platform for developing an IoT application. Attaching a cable to upload a new program can be a hassle when the node is on a workbench. Imagine what it's like when the node is mounted high on a wall!
Messing around with the code is a great way to get comfortable with scripting. Python is easy to read, so try making some other changes and uploading new code to the node to see what will happen. If everything goes wrong, you can always reload the original HolidayLightShow.py file and start over.